home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / iproute.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  22KB  |  845 lines

  1. /* Lower half of IP, consisting of gateway routines
  2.  * Includes routing and options processing code
  3.  *
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  *
  6.  * Mods by PA0GRI
  7.  */
  8. #include "global.h"
  9. #include "config.h"
  10. #include "mbuf.h"
  11. #include "socket.h"
  12. #include "iface.h"
  13. #include "timer.h"
  14. #include "internet.h"
  15. #include "ip.h"
  16. #include "netuser.h"
  17. #include "icmp.h"
  18. #include "rip.h"
  19. #include "trace.h"
  20. #include "pktdrvr.h"
  21. #include "bootp.h"
  22.  
  23.  
  24. struct route *Routes[32][HASHMOD];    /* Routing table */
  25. struct route R_default = {        /* Default route entry */
  26.     NULLROUTE, NULLROUTE,
  27.     0,0,0,
  28.     RIP_INFINITY        /* Init metric to infinity */
  29. };
  30.  
  31. static struct rt_cache Rt_cache;
  32.  
  33. #ifdef IPACCESS
  34. struct rtaccess *IPaccess = NULLACCESS; /* access list */
  35. #endif
  36.  
  37. /* Initialize modulo lookup table used by hash_ip() in pcgen.asm */
  38. void
  39. ipinit()
  40. {
  41.     int i;
  42.  
  43.     for(i=0;i<256;i++)
  44.         Hashtab[i] = i % HASHMOD;
  45. }
  46.  
  47. /* Route an IP datagram. This is the "hopper" through which all IP datagrams,
  48.  * coming or going, must pass.
  49.  *
  50.  * "rxbroadcast" is set to indicate that the packet came in on a subnet
  51.  * broadcast. The router will kick the packet upstairs regardless of the
  52.  * IP destination address.
  53.  */
  54.  
  55. int
  56. ip_route(i_iface,bp,rxbroadcast)
  57. struct iface *i_iface;    /* Input interface */
  58. struct mbuf *bp;    /* Input packet */
  59. int rxbroadcast;    /* True if packet had link broadcast address */
  60. {
  61.     struct ip ip;            /* IP header being processed */
  62.     int16 ip_len;            /* IP header length */
  63.     int16 length;            /* Length of data portion */
  64.     int32 gateway;            /* Gateway IP address */
  65.     register struct route *rp;    /* Route table entry */
  66.     struct iface *iface;        /* Output interface, possibly forwarded */
  67.     int16 offset;            /* Offset into current fragment */
  68.     int16 mf_flag;            /* Original datagram MF flag */
  69.     int strict = 0;            /* Strict source routing flag */
  70.     char prec;            /* Extracted from tos field */
  71.     char del;
  72.     char tput;
  73.     char rel;
  74.     int16 opt_len;        /* Length of current option */
  75.     char *opt;        /* -> beginning of current option */
  76.     int i;
  77.     struct mbuf *tbp;
  78.     int ckgood = IP_CS_OLD; /* Has good checksum without modification */
  79. #ifdef IPACCESS
  80.     int16 srcport, dstport;    /* for use in access checking */
  81.     struct rtaccess *tpacc;    /* temporary for access checking */
  82. #endif
  83.     int pointer;        /* Relative pointer index for sroute/rroute */
  84.  
  85.     if(i_iface != NULLIF){
  86.         ipInReceives++;    /* Not locally generated */
  87.         i_iface->iprecvcnt++;
  88.     }
  89.     if(len_p(bp) < IPLEN){
  90.         /* The packet is shorter than a legal IP header */
  91.         ipInHdrErrors++;
  92.         free_p(bp);
  93.         return -1;
  94.     }
  95.     /* Sneak a peek at the IP header's IHL field to find its length */
  96.     ip_len = (bp->data[0] & 0xf) << 2;
  97.     if(ip_len < IPLEN){
  98.         /* The IP header length field is too small */
  99.         ipInHdrErrors++;
  100.         free_p(bp);
  101.         return -1;
  102.     }
  103.     if(cksum(NULLHEADER,bp,ip_len) != 0){
  104.         /* Bad IP header checksum; discard */
  105.         ipInHdrErrors++;
  106.         free_p(bp);
  107.         return -1;
  108.     }
  109.     /* Extract IP header */
  110.     ntohip(&ip,&bp);
  111.  
  112.     if(ip.version != IPVERSION){
  113.         /* We can't handle this version of IP */
  114.         ipInHdrErrors++;
  115.         free_p(bp);
  116.         return -1;
  117.     }
  118.  
  119.     /* IP logging added - WG7J
  120.      * only if not an AX.25 interface, since those are already
  121.      * logged in ax_recv() in ax25.c
  122.      */
  123.     if((i_iface != NULLIF) && (i_iface->type != CL_AX25) &&
  124.        (i_iface->flags & LOG_IPHEARD) )
  125.         log_ipheard(ip.source,i_iface);
  126.  
  127.     /* Trim data segment if necessary. */
  128.     length = ip.length - ip_len;    /* Length of data portion */
  129.     trim_mbuf(&bp,length);    
  130.                 
  131. #ifndef UNIX
  132.     /* If we're running low on memory, return a source quench */
  133.     if(!rxbroadcast && availmem() < Memthresh)
  134.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULLICMP);
  135. #endif
  136.  
  137.     /* Process options, if any. Also compute length of secondary IP
  138.      * header in case fragmentation is needed later
  139.      */
  140.     strict = 0;
  141.     for(i=0;i<ip.optlen;i += opt_len){
  142.  
  143.         /* First check for the two special 1-byte options */
  144.         switch(ip.options[i] & OPT_NUMBER){
  145.         case IP_EOL:
  146.             goto no_opt;    /* End of options list, we're done */
  147.         case IP_NOOP:
  148.             opt_len = 1;
  149.             continue;    /* No operation, skip to next option */
  150.         }
  151.         /* Not a 1-byte option, so ensure that there's at least
  152.          * two bytes of option left, that the option length is
  153.          * at least two, and that there's enough space left for
  154.          * the specified option length.
  155.          */
  156.         if(ip.optlen - i < 2
  157.          || ((opt_len = uchar(ip.options[i+1])) < 2)
  158.          || ip.optlen - i < opt_len){
  159.             /* Truncated option, send ICMP and drop packet */
  160.             if(!rxbroadcast){
  161.                 union icmp_args icmp_args;
  162.  
  163.                 icmp_args.pointer = IPLEN + i;
  164.                 icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  165.             }
  166.             free_p(bp);
  167.             return -1;
  168.         }
  169.         opt = &ip.options[i];
  170.  
  171.         switch(opt[0] & OPT_NUMBER){
  172.         case IP_SSROUTE:    /* Strict source route & record route */
  173.             strict = 1;    /* note fall-thru */
  174.         case IP_LSROUTE:    /* Loose source route & record route */
  175.             /* Source routes are ignored unless we're in the
  176.              * destination field
  177.              */
  178.             if(opt_len < 3){
  179.                 /* Option is too short to be a legal sroute.
  180.                  * Send an ICMP message and drop it.
  181.                  */
  182.                 if(!rxbroadcast){
  183.                     union icmp_args icmp_args;
  184.  
  185.                     icmp_args.pointer = IPLEN + i;
  186.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  187.                 }
  188.                 free_p(bp);
  189.                 return -1;
  190.             }
  191.             if(ismyaddr(ip.dest) == NULLIF)
  192.                 break;    /* Skip to next option */
  193.             pointer = uchar(opt[2]);
  194.             if(pointer + 4 > opt_len)
  195.                 break;    /* Route exhausted; it's for us */
  196.  
  197.             /* Put address for next hop into destination field,
  198.              * put our address into the route field, and bump
  199.              * the pointer. We've already ensured enough space.
  200.              */
  201.             ip.dest = get32(&opt[pointer]);
  202.             put32(&opt[pointer],locaddr(ip.dest));
  203.             opt[2] += 4;
  204.             ckgood = IP_CS_NEW;
  205.             break;
  206.         case IP_RROUTE:    /* Record route */
  207.             if(opt_len < 3){
  208.                 /* Option is too short to be a legal rroute.
  209.                  * Send an ICMP message and drop it.
  210.                  */
  211.                 if(!rxbroadcast){
  212.                     union icmp_args icmp_args;
  213.  
  214.                     icmp_args.pointer = IPLEN + i;
  215.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  216.                 }
  217.                 free_p(bp);
  218.                 return -1;
  219.             }                
  220.             pointer = uchar(opt[2]);
  221.             if(pointer + 4 > opt_len){
  222.                 /* Route area exhausted; send an ICMP msg */
  223.                 if(!rxbroadcast){
  224.                     union icmp_args icmp_args;
  225.  
  226.                     icmp_args.pointer = IPLEN + i;
  227.                     icmp_output(&ip,bp,ICMP_PARAM_PROB,0,&icmp_args);
  228.                 }
  229.                 /* Also drop if odd-sized */
  230.                 if(pointer != opt_len){
  231.                     free_p(bp);
  232.                     return -1;
  233.                 }
  234.             } else {
  235.                 /* Add our address to the route.
  236.                  * We've already ensured there's enough space.
  237.                  */
  238.                 put32(&opt[pointer],locaddr(ip.dest));
  239.                  opt[2] += 4;
  240.                 ckgood = IP_CS_NEW;
  241.             }
  242.             break;
  243.         }
  244.     }
  245. no_opt:
  246.  
  247.     /* See if it's a broadcast or addressed to us, and kick it upstairs */
  248.     if(ismyaddr(ip.dest) != NULLIF || rxbroadcast ||
  249.         (WantBootp && bootp_validPacket(&ip, &bp))){
  250. #ifdef    GWONLY
  251.     /* We're only a gateway, we have no host level protocols */
  252.         if(!rxbroadcast)
  253.             icmp_output(&ip,bp,ICMP_DEST_UNREACH,
  254.              ICMP_PROT_UNREACH,NULLICMP);
  255.         ipInUnknownProtos++;
  256.         free_p(bp);
  257. #else
  258.         ip_recv(i_iface,&ip,bp,rxbroadcast);
  259. #endif
  260.         return 0;
  261.     }
  262.     /* Packet is not destined to us. If it originated elsewhere, count
  263.      * it as a forwarded datagram.
  264.      */
  265.     if(i_iface != NULLIF)
  266.         ipForwDatagrams++;
  267.  
  268.     /* Adjust the header checksum to allow for the modified TTL */        
  269.     ip.checksum += 0x100;
  270.     if((ip.checksum & 0xff00) == 0)
  271.         ip.checksum++;    /* end-around carry */
  272.  
  273.     /* Decrement TTL and discard if zero. We don't have to check
  274.      * rxbroadcast here because it's already been checked
  275.      */
  276.     if(--ip.ttl == 0){
  277.         /* Send ICMP "Time Exceeded" message */
  278.         icmp_output(&ip,bp,ICMP_TIME_EXCEED,0,NULLICMP);
  279.         ipInHdrErrors++;
  280.         free_p(bp);
  281.         return -1;
  282.     }
  283.     /* Look up target address in routing table */
  284.     if((rp = rt_lookup(ip.dest)) == NULLROUTE){
  285.         /* No route exists, return unreachable message (we already
  286.          * know this can't be a broadcast)
  287.          */
  288.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  289.         free_p(bp);
  290.         ipOutNoRoutes++;
  291.         return -1;
  292.     }
  293.     rp->uses++;
  294.  
  295.     /* Check for output forwarding and divert if necessary */
  296.     iface = rp->iface;
  297.     if(iface->forw != NULLIF)
  298.         iface = iface->forw;
  299.  
  300. #ifdef IPACCESS
  301. /* At this point we've decided to send the packet out 'iface' (unless it
  302. won't fragment).  Check ip.protocol for tcp or udp.
  303. Should probably have counter on number of dropped packets.
  304. */
  305. #ifdef __GNUC__
  306.     dstport = 0;        /* actually, this one may be for real... */
  307. #endif
  308.     if((ip.protocol == TCP_PTCL) || (ip.protocol==UDP_PTCL)) {
  309.         /* pull up source & destination port */
  310.         srcport = get16(&(bp->data[0])); /*done for futures & debug*/
  311.         dstport = get16(&(bp->data[2]));
  312.     }
  313.     /* for backwards compatibility, if there are *no* entries */
  314.     /* we ignore access control, so everything is legal. Any  */
  315.     /* entry for an iface means default is to drop if no      */
  316.     /* permission found  */
  317.     for( tpacc = IPaccess;tpacc != NULLACCESS;tpacc=tpacc->nxtiface) {
  318.         /*find a matching iface*/
  319.         if(tpacc->iface == iface ){ /* Needs to be authorized */
  320.             if(!ip_check(tpacc, ip.protocol, ip.source, ip.dest, dstport))
  321.                 break;
  322.             /* not found, throw it away. */
  323.             /* if NO access, then drop & increment counter */
  324.             /* see new(er) RFC for proper ICMP codes */
  325.             /* maybe counter is in MIB? else create.*/
  326.             icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  327.             ipOutNoRoutes++;
  328.             free_p(bp);
  329.             return -1;
  330.         }
  331.     }
  332. #endif
  333.     /* Find gateway; zero gateway in routing table means "send direct" */
  334.     if(rp->gateway == 0)
  335.         gateway = ip.dest;
  336.     else
  337.         gateway = rp->gateway;
  338.  
  339.     if(strict && gateway != ip.dest){
  340.         /* Strict source routing requires a direct entry
  341.          * Again, we know this isn't a broadcast
  342.          */
  343.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_ROUTE_FAIL,NULLICMP);
  344.         free_p(bp);
  345.         ipOutNoRoutes++;
  346.         return -1;
  347.     }
  348.     prec = PREC(ip.tos);
  349.     del = ip.tos & DELAY;
  350.     tput = ip.tos & THRUPUT;
  351.     rel = ip.tos & RELIABILITY;
  352.  
  353.     if(ip.length <= iface->mtu){
  354.         /* Datagram smaller than interface MTU; put header
  355.          * back on and send normally.
  356.          */
  357.         if((tbp = htonip(&ip,bp,ckgood)) == NULLBUF){
  358.             free_p(bp);
  359.             return -1;
  360.         }
  361.         iface->ipsndcnt++;
  362.         return (*iface->send)(tbp,iface,gateway,prec,del,tput,rel);
  363.     }
  364.     /* Fragmentation needed */
  365.     if(ip.flags.df){
  366.         /* Don't Fragment set; return ICMP message and drop */
  367.         union icmp_args icmp_args;
  368.  
  369.         icmp_args.mtu = iface->mtu;
  370.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED,&icmp_args);
  371.         free_p(bp);
  372.         ipFragFails++;
  373.         return -1;
  374.     }
  375.     /* Create fragments */
  376.     offset = ip.offset;
  377.     mf_flag = ip.flags.mf;        /* Save original MF flag */
  378.     while(length != 0){        /* As long as there's data left */
  379.         int16 fragsize;        /* Size of this fragment's data */
  380.         struct mbuf *f_data;    /* Data portion of fragment */
  381.  
  382.         /* After the first fragment, should remove those
  383.          * options that aren't supposed to be copied on fragmentation
  384.          */
  385.         ip.offset = offset;
  386.         if(length + ip_len <= iface->mtu){
  387.             /* Last fragment; send all that remains */
  388.             fragsize = length;
  389.             ip.flags.mf = mf_flag;    /* Pass original MF flag */
  390.         } else {
  391.             /* More to come, so send multiple of 8 bytes */
  392.             fragsize = (iface->mtu - ip_len) & 0xfff8;
  393.             ip.flags.mf = 1;
  394.         }
  395.         ip.length = fragsize + ip_len;
  396.  
  397.         /* Duplicate the fragment */
  398.         dup_p(&f_data,bp,offset,fragsize);
  399.         if(f_data == NULLBUF){
  400.             free_p(bp);
  401.             ipFragFails++;
  402.             return -1;
  403.         }
  404.         /* Put IP header back on, recomputing checksum */
  405.         if((tbp = htonip(&ip,f_data,IP_CS_NEW)) == NULLBUF){
  406.             free_p(f_data);
  407.             free_p(bp);
  408.             ipFragFails++;
  409.             return -1;
  410.         }
  411.         /* and ship it out */
  412.         if((*iface->send)(tbp,iface,gateway,prec,del,tput,rel) == -1){
  413.             ipFragFails++;
  414.             free_p(bp);
  415.             return -1;
  416.         }
  417.         iface->ipsndcnt++;
  418.         ipFragCreates++;
  419.         offset += fragsize;
  420.         length -= fragsize;
  421.     }
  422.     ipFragOKs++;
  423.     free_p(bp);
  424.     return 0;
  425. }
  426.  
  427. #ifdef ENCAP
  428. int
  429. ip_encap(bp,iface,gateway,prec,del,tput,rel)
  430. struct mbuf *bp;
  431. struct iface *iface;
  432. int32 gateway;
  433. int prec;
  434. int del;
  435. int tput;
  436. int rel;
  437. {
  438.     struct ip ip;
  439.  
  440.     dump(iface,IF_TRACE_OUT,CL_NONE,bp);
  441.     iface->rawsndcnt++;
  442.     iface->lastsent = secclock();
  443.  
  444.     if(gateway == 0L){
  445.         /* Gateway must be specified */
  446.         ntohip(&ip,&bp);
  447.         icmp_output(&ip,bp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULLICMP);
  448.         free_p(bp);
  449.         ipOutNoRoutes++;
  450.         return -1;
  451.     }
  452.     return ip_send(INADDR_ANY,gateway,IP_PTCL,0,0,bp,0,0,0);
  453. }
  454. #endif /*ENCAP*/
  455.  
  456. /* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
  457. struct route *
  458. rt_add(target,bits,gateway,iface,metric,ttl,private)
  459. int32 target;        /* Target IP address prefix */
  460. unsigned int bits;    /* Size of target address prefix in bits (0-32) */
  461. int32 gateway;        /* Optional gateway to be reached via interface */
  462. struct iface *iface;    /* Interface to which packet is to be routed */
  463. int32 metric;        /* Metric for this route entry */
  464. int32 ttl;        /* Lifetime of this route entry in sec */
  465. char private;        /* Inhibit advertising this entry ? */
  466. {
  467.     struct route *rp,**hp;
  468. #ifdef ENCAP
  469.     struct route *rptmp;
  470.     int32 gwtmp;
  471. #endif
  472.  
  473.     if(iface == NULLIF)
  474.         return NULLROUTE;
  475.  
  476.     if(bits == 32 && ismyaddr(target))
  477.         return NULLROUTE;    /* Don't accept routes to ourselves */
  478.  
  479.     if(bits > 32)
  480.         bits = 32;        /* Bulletproofing */
  481. #ifdef ENCAP
  482.     /* Encapsulated routes must specify gateway, and it can't be
  483.      *  ourselves
  484.      */
  485.     if(iface == &Encap && (gateway == 0 || ismyaddr(gateway)))
  486.         return NULLROUTE;
  487. #endif
  488.  
  489.     Rt_cache.route = NULLROUTE;    /* Flush cache */
  490.  
  491.     /* Mask off don't-care bits of target */
  492.     target &= ~0L << (32-bits);
  493.  
  494.     /* Zero bits refers to the default route */
  495.     if(bits == 0){
  496.         rp = &R_default;
  497.     } else {
  498.         rp = rt_blookup(target,bits);
  499.     }
  500.     if(rp == NULLROUTE){
  501.         /* The target is not already in the table, so create a new
  502.          * entry and put it in.
  503.          */
  504.         rp = (struct route *)callocw(1,sizeof(struct route));
  505.         /* Insert at head of table */
  506.         rp->prev = NULLROUTE;
  507.         hp = &Routes[bits-1][hash_ip(target)];
  508.         rp->next = *hp;
  509.         if(rp->next != NULLROUTE)
  510.             rp->next->prev = rp;
  511.         *hp = rp;
  512.         rp->uses = 0;
  513.     }
  514.     rp->target = target;
  515.     rp->bits = bits;
  516.     rp->gateway = gateway;
  517.     rp->metric = metric;
  518.     rp->iface = iface;
  519.     rp->flags = private ? RTPRIVATE : 0;    /* Should anyone be told of this route? */
  520.     rp->timer.func = rt_timeout;  /* Set the timer field */
  521.     rp->timer.arg = (void *)rp;
  522.     set_timer(&rp->timer,ttl*1000L);
  523.     stop_timer(&rp->timer);
  524.     start_timer(&rp->timer); /* start the timer if appropriate */
  525.  
  526. #ifdef ENCAP
  527.     /* Check to see if this created an encapsulation loop */
  528.     gwtmp = gateway;
  529.     for(;;){
  530.         rptmp = rt_lookup(gwtmp);
  531.         if(rptmp == NULLROUTE)
  532.             break;    /* No route to gateway, so no loop */
  533.         if(rptmp->iface != &Encap)
  534.             break;    /* Non-encap interface, so no loop */
  535.         if(rptmp == rp){
  536.             rt_drop(target,bits);    /* Definite loop */
  537.             return NULLROUTE;
  538.         }
  539.         if(rptmp->gateway != 0)
  540.             gwtmp = rptmp->gateway;
  541.     }
  542. #endif
  543.     return rp;
  544. }
  545.  
  546. /* Remove an entry from the IP routing table. Returns 0 on success, -1
  547.  * if entry was not in table.
  548.  */
  549. int
  550. rt_drop(target,bits)
  551. int32 target;
  552. unsigned int bits;
  553. {
  554.     register struct route *rp;
  555.  
  556.     Rt_cache.route = NULLROUTE;    /* Flush the cache */
  557.  
  558.     if(bits == 0){
  559.         /* Nail the default entry */
  560.         stop_timer(&R_default.timer);
  561.         R_default.iface = NULLIF;
  562.         return 0;
  563.     }
  564.     if(bits > 32)
  565.         bits = 32;
  566.  
  567.     /* Mask off target according to width */
  568.     target &= ~0L << (32-bits);
  569.  
  570.     /* Search appropriate chain for existing entry */
  571.     for(rp = Routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  572.         if(rp->target == target)
  573.             break;
  574.     }
  575.     if(rp == NULLROUTE)
  576.         return -1;    /* Not in table */
  577.  
  578.     stop_timer(&rp->timer);
  579.     if(rp->next != NULLROUTE)
  580.         rp->next->prev = rp->prev;
  581.     if(rp->prev != NULLROUTE)
  582.         rp->prev->next = rp->next;
  583.     else
  584.         Routes[bits-1][hash_ip(target)] = rp->next;
  585.  
  586.     free((char *)rp);
  587.     return 0;
  588. }
  589. #ifdef    notdef
  590.  
  591. /* Compute hash function on IP address */
  592. static int16
  593. hash_ip(addr)
  594. register int32 addr;
  595. {
  596.     register int16 ret;
  597.  
  598.     ret = hiword(addr);
  599.     ret ^= loword(addr);
  600.     return (int16)(ret % HASHMOD);
  601. }
  602. #endif
  603. #ifndef    GWONLY
  604. /* Given an IP address, return the MTU of the local interface used to
  605.  * reach that destination. This is used by TCP to avoid local fragmentation
  606.  */
  607. int16
  608. ip_mtu(addr)
  609. int32 addr;
  610. {
  611.     register struct route *rp;
  612.     struct iface *iface;
  613.  
  614.     rp = rt_lookup(addr);
  615.     if(rp == NULLROUTE || rp->iface == NULLIF)
  616.         return 0;
  617.  
  618.     iface = rp->iface;
  619.     if(iface->forw != NULLIF)
  620.         return iface->forw->mtu;
  621.     else
  622.         return iface->mtu;
  623. }
  624. /* Given a destination address, return the IP address of the local
  625.  * interface that will be used to reach it. If there is no route
  626.  * to the destination, pick the first non-loopback address.
  627.  */
  628. int32
  629. locaddr(addr)
  630. int32 addr;
  631. {
  632.     register struct route *rp;
  633.     struct iface *ifp;
  634.  
  635.     if(ismyaddr(addr) != NULLIF)
  636.         return addr;    /* Loopback case */
  637.  
  638.     rp = rt_lookup(addr);
  639.     if(rp != NULLROUTE && rp->iface != NULLIF)
  640.         ifp = rp->iface;
  641.     else {
  642.         /* No route currently exists, so just pick the first real
  643.          * interface and use its address
  644.          */
  645.         for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  646. #ifdef ENCAP
  647.             if(ifp != &Loopback && ifp != &Encap)
  648. #else
  649.             if(ifp != &Loopback)
  650. #endif
  651.                 break;
  652.         }
  653.     }
  654.     if(ifp == NULLIF || ifp == &Loopback)
  655.         return 0;    /* No dice */
  656.  
  657. #ifdef ENCAP
  658.     if(ifp == &Encap){
  659.         /* Recursive call - we assume that there are no circular
  660.          * encapsulation references in the routing table!!
  661.          * (There is a check at the end of rt_add() that goes to
  662.          * great pains to ensure this.)
  663.          */
  664.         /* Next couple of lines are a point of discussion
  665.          * The ultimate source for encaptulation is the local
  666.          * IP address. Phil looks for the address of the addres
  667.          * to be used, ending up with the wrong one (in my oppinion)
  668.          * If you disagree set encap ip address to what you want.
  669.          */
  670.         if(Encap.addr != 0)
  671.             return Encap.addr;
  672. #ifdef notdef
  673.         return locaddr(rp->gateway);
  674. #else
  675.         return Ip_addr;
  676. #endif
  677.     }
  678. #endif /*ENCAP*/
  679.     if(ifp->forw != NULLIF)
  680.         return ifp->forw->addr;
  681.     else
  682.         return ifp->addr;
  683. }
  684. #endif /*GWONLY*/
  685. /* Look up target in hash table, matching the entry having the largest number
  686.  * of leading bits in common. Return default route if not found;
  687.  * if default route not set, return NULLROUTE
  688.  */
  689. struct route *
  690. rt_lookup(target)
  691. int32 target;
  692. {
  693.     register struct route *rp;
  694.     int bits;
  695.     int32 tsave;
  696.     int32 mask;
  697.  
  698.     /* Examine cache first */
  699.     if(target == Rt_cache.target && Rt_cache.route != NULLROUTE)
  700.         return Rt_cache.route;
  701.  
  702.     tsave = target;
  703.  
  704.     mask = ~0L;    /* All ones */
  705.     for(bits = 31;bits >= 0; bits--){
  706.         target &= mask;
  707.         for(rp = Routes[bits][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  708.             if(rp->target == target){
  709.                 /* Stash in cache and return */
  710.                 Rt_cache.target = tsave;
  711.                 Rt_cache.route = rp;
  712.                 return rp;
  713.             }
  714.         }
  715.         mask <<= 1;
  716.     }
  717.     if(R_default.iface != NULLIF){
  718.         Rt_cache.target = tsave;
  719.         Rt_cache.route = &R_default;
  720.         return &R_default;
  721.     } else
  722.         return NULLROUTE;
  723. }
  724. /* Search routing table for entry with specific width */
  725. struct route *
  726. rt_blookup(target,bits)
  727. int32 target;
  728. unsigned int bits;
  729. {
  730.     register struct route *rp;
  731.  
  732.     if(bits == 0){
  733.         if(R_default.iface != NULLIF)
  734.             return &R_default;
  735.         else
  736.             return NULLROUTE;
  737.     }
  738.     /* Mask off target according to width */
  739.     target &= ~0L << (32-bits);
  740.  
  741.     for(rp = Routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
  742.         if(rp->target == target){
  743.             return rp;
  744.         }
  745.     }
  746.     return NULLROUTE;
  747. }
  748. /* Scan the routing table. For each entry, see if there's a less-specific
  749.  * one that points to the same interface and gateway. If so, delete
  750.  * the more specific entry, since it is redundant.
  751.  */
  752. void
  753. rt_merge(trace)
  754. int trace;
  755. {
  756.     int bits,i,j;
  757.     struct route *rp,*rpnext,*rp1;
  758.  
  759.     for(bits=32;bits>0;bits--){
  760.         for(i = 0;i<HASHMOD;i++){
  761.             for(rp = Routes[bits-1][i];rp != NULLROUTE;rp = rpnext){
  762.                 rpnext = rp->next;
  763.                 for(j=bits-1;j >= 0;j--){
  764.                     if((rp1 = rt_blookup(rp->target,(unsigned)j)) != NULLROUTE
  765.                      && rp1->iface == rp->iface
  766.                      && rp1->gateway == rp->gateway){
  767.                         if(trace > 1)
  768.                             printf("merge %s %d\n",
  769.                              inet_ntoa(rp->target),
  770.                              rp->bits);
  771.                         rt_drop(rp->target,rp->bits);
  772.                         break;
  773.                     }
  774.                 }
  775.             }
  776.         }
  777.     }
  778. }
  779. #ifdef IPACCESS
  780. /* check to see if packet is "authorized".  Returns 0 if matching */
  781. /* permit record is found, -1 if not found or deny record found */
  782. int
  783. ip_check(accptr,protocol,src,dest,port)
  784. struct rtaccess *accptr;
  785. int16 protocol,port;
  786. int32 src,dest;
  787. {
  788.     int32 smask,tmask;
  789.  
  790.     for(;accptr != NULLACCESS;accptr = accptr->nxtbits) {
  791.         if ((accptr->protocol == 0) ||
  792.              (accptr->protocol == protocol)) {
  793.             smask = ~0L << (32 - accptr->sbits);
  794.             tmask = ~0L << (32 - accptr->bits);
  795.             if ((accptr->source == (smask & src)) &&
  796.                 (accptr->target == (tmask & dest)) &&
  797.                 ((accptr->lowport == 0) ||
  798.                  ((port >= accptr->lowport) &&
  799.                   (port <= accptr->highport)))) {
  800.                 return (accptr->status);
  801.             }
  802.         }
  803.     }
  804.     return -1; /* fall through to here if not found */
  805. }
  806. /* add an entry to the access control list */
  807. /* not a lot of error checking 8-) */
  808. void
  809. addaccess(protocol,source,sbits,target,tbits,ifp,low,high,permit)
  810. int16 protocol;            /* IP protocol */
  811. int32 source,target;        /* Source & target IP address prefix */
  812. unsigned int sbits,tbits;    /* Size of address prefix in bits (0-32) */
  813. struct iface *ifp;        /* Interface to which packet may be routed */
  814. int16 low;
  815. int16 high;
  816. int16 permit;
  817. {
  818.     struct rtaccess *tpacc; /*temporary*/
  819.     struct rtaccess *holder; /*for the new record*/
  820.  
  821.     holder = (struct rtaccess *)callocw(1,sizeof(struct rtaccess));
  822.     holder->nxtiface = NULLACCESS;
  823.     holder->nxtbits = NULLACCESS;
  824.     holder->protocol = protocol;
  825.     holder->source = source;
  826.     holder->sbits = sbits;
  827.     holder->target = target;
  828.     holder->bits = tbits;
  829.     holder->iface = ifp;
  830.     holder->lowport = low;
  831.     holder->highport = high;
  832.     holder->status = permit;
  833.     for(tpacc = IPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtiface)
  834.         if(tpacc->iface == ifp) { /* get to end */
  835.             while(tpacc->nxtbits != NULLACCESS)
  836.                 tpacc = tpacc->nxtbits;
  837.             tpacc->nxtbits = holder;
  838.             return;
  839.         }
  840.   /* iface wasn't found, so just add at head of list */
  841.     holder->nxtiface = IPaccess;
  842.     IPaccess = holder;
  843. }
  844. #endif
  845.